package org.leo.dm.component.util;

import java.sql.Connection;
import java.sql.PreparedStatement;

import org.leo.dm.common.exception.DpException;
import org.leo.dm.common.exception.DpExceptionCodeEnum;
import org.leo.dm.component.callback.DbExceptionCallback;
import org.leo.dm.util.ToUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * Created on 2016年2月17日
 * <p>
 * Description db方式执行批处理操作工具类
 * <p>
 * Copyright neusoft (c) 2015 .
 * 
 * @author xiao_h
 *
 */
public class DbBatch {
	Logger log = LoggerFactory.getLogger(this.getClass());

	private ToUtil util;

	private DbExceptionCallback dbExceptionCallback;

	public void setDbExceptionCallback(DbExceptionCallback dbExceptionCallback) {
		this.dbExceptionCallback = dbExceptionCallback;
	}

	protected Connection conn;
	protected PreparedStatement ps;

	protected final int defaltBatchSize = 10000;

	protected int batchSize = defaltBatchSize;

	public void setBatchSize(int batchSize) {
		this.batchSize = batchSize;
	}

	private DbWriteHelper batchHelper;

	public DbWriteHelper getBatchHelper() {
		return batchHelper;
	}

	public void setBatchHelper(DbWriteHelper batchHelper) {
		this.batchHelper = batchHelper;
	}

	private int count;

	protected StringBuffer replaceColumns = new StringBuffer("");
	protected StringBuffer replaceWhereColumns = new StringBuffer("");
	protected StringBuffer replaceValues = new StringBuffer("");

	private String sql;

	public DbBatch() {

	}

	private String tableName;
	private int tableAlreadyCounter;

	public DbBatch(Connection con, String tableName, DmlEnum dmlEnum, Object[] columnNameList, Object[] whereColumnNameList) throws Exception {
		this.tableName = tableName;

		if (con == null) {
			throw new DpException(DpExceptionCodeEnum.PARAM_ERROR, "Connection为空 无法执行");
		}
		if (tableName == null) {
			throw new DpException(DpExceptionCodeEnum.PARAM_ERROR, "tableName为空 无法执行");
		}
		if (dmlEnum == null) {
			throw new DpException(DpExceptionCodeEnum.PARAM_ERROR, "DML类型为空 无法执行");
		}
		if (columnNameList == null) {
			throw new DpException(DpExceptionCodeEnum.PARAM_ERROR, "预处理参数为空 无法执行");
		}
		if (whereColumnNameList == null) {
			throw new DpException(DpExceptionCodeEnum.PARAM_ERROR, "预处理条件参数为空 无法执行");
		}
		switch (dmlEnum) {
		case INSERT:
			initInsertSql(columnNameList);
			break;
		case UPDATE:
			initUpdateSql(columnNameList, whereColumnNameList);
			break;
		case DELETE:
			initDeleteSql(whereColumnNameList);
			break;
		default:
			throw new DpException(DpExceptionCodeEnum.PARAM_ERROR, "DML类型未选择 无法执行");
			// break;
		}
		initDb(con);

		util = new ToUtil();
	}

	private void initInsertSql(Object[] columnNameList) {
		int nameListSize = columnNameList.length;
		for (int i = 0; i < nameListSize; i++) {
			if (i == 0) {
				replaceColumns.append(columnNameList[i]);
				replaceValues.append("?");
			} else {
				replaceColumns.append(",").append(columnNameList[i]);
				replaceValues.append(",?");
			}
		}
		sql = "insert into " + tableName + " (" + replaceColumns.toString() + ") " + " values (" + replaceValues.toString() + ")";
		log.info(sql);
	}

	private void initUpdateSql(Object[] columnNameList, Object[] whereColumnNameList) {
		int nameListSize = columnNameList.length;
		for (int i = 0; i < nameListSize; i++) {
			if (i == 0) {
				replaceColumns.append(columnNameList[i] + "=?");
			} else {
				replaceColumns.append(",").append(columnNameList[i] + "=?");
			}
		}
		int whereColumnNameListSize = whereColumnNameList.length;
		for (int i = 0; i < whereColumnNameListSize; i++) {
			if (i == 0) {
				replaceWhereColumns.append(whereColumnNameList[i] + "=?");
			} else {
				replaceWhereColumns.append(" and ").append(whereColumnNameList[i] + "=?");
			}
		}
		sql = "update " + tableName + " set " + replaceColumns.toString() + " where " + replaceWhereColumns.toString();
		log.info(sql);
	}

	private void initDeleteSql(Object[] whereColumnNameList) {
		int nameListSize = whereColumnNameList.length;
		for (int i = 0; i < nameListSize; i++) {
			if (i == 0) {
				replaceWhereColumns.append(whereColumnNameList[i] + "=?");
			} else {
				replaceWhereColumns.append(" and ").append(whereColumnNameList[i] + "=?");
			}
		}
		sql = "delete from " + tableName + " where " + replaceWhereColumns.toString();
		log.info(sql);
	}

	private void initDb(Connection con) throws Exception {
		try {
			conn = con;
			conn.setAutoCommit(false);
			ps = conn.prepareStatement(sql);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void last() throws Exception {
		try {
			log.info("等待执行中");
			int excuteNum = ps.executeBatch().length;
			tableAlreadyCounter = tableAlreadyCounter + excuteNum;
			batchHelper.alreadyRunCount = batchHelper.alreadyRunCount + excuteNum;
//			if (batchHelper.getTableCount().containsKey(tableName)) {
//				batchHelper.getTableCount().put(tableName, batchHelper.getTableCount().get(tableName) + tableAlreadyCounter);
//			} else {
				batchHelper.getTableCount().put(tableName, tableAlreadyCounter);
//			}
			conn.commit();

			this.util.takeTimeEnd("数据量：" + count + " 条数/s：" + (count / this.util.getDuration()));
		} catch (Exception e) {
			e.printStackTrace();
			try {
				conn.rollback();
				// 业务性质回滚
				dbExceptionCallback.handle(null);
				log.info("事务回滚");
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			throw e;
		} finally {
			DbUtil.close(null, ps, null);
		}
	}

	public String handle(Object[] valueList) throws Exception {
		try {
			int valueListSize = valueList.length;
			for (int i = 0; i < valueListSize; i++) {
				// log.info(i + 1 + "~~~~~~~~~~~~~~" + valueList[i]);
				ps.setObject(i + 1, valueList[i]);
			}
			ps.addBatch();

			if (++count % batchSize == 0) {
				log.info("等待执行中");
				ToUtil tu1 = new ToUtil();
				int excuteNum = ps.executeBatch().length;
				tableAlreadyCounter = tableAlreadyCounter + excuteNum;
				batchHelper.alreadyRunCount = batchHelper.alreadyRunCount + excuteNum;
//				if (batchHelper.getTableCount().containsKey(tableName)) {
//					batchHelper.getTableCount().put(tableName, batchHelper.getTableCount().get(tableName) + tableAlreadyCounter);
//				} else {
					batchHelper.getTableCount().put(tableName, tableAlreadyCounter);
//				}

				conn.commit();
				tu1.takeTimePrex("执行花费时间");
				ps.clearParameters();
				ps.clearBatch();
				// util.ignore();
				this.util.takeTimeEnd("数据量：" + count + " 条数/s：" + (count / this.util.getDuration()));
			}
		} catch (Exception e) {
			e.printStackTrace();
			try {
				conn.rollback();
				// 业务性质回滚
				dbExceptionCallback.handle(null);
				log.info("事务回滚");
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			throw e;
		}

		return null;
	}

	public void close() throws Exception {
		try {
			DbUtil.close(null, ps, conn);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

}
